package cn.youqu.happy.module.youqu.service.userAssess;

import cn.youqu.happy.framework.common.pojo.PageResult;
import cn.youqu.happy.framework.common.util.string.StrUtils;
import cn.youqu.happy.module.member.dal.dataobject.user.MemberUserDO;
import cn.youqu.happy.module.member.service.user.MemberUserService;
import cn.youqu.happy.module.youqu.controller.admin.userAssess.vo.UserAssessCreateReqVO;
import cn.youqu.happy.module.youqu.controller.admin.userAssess.vo.UserAssessExportReqVO;
import cn.youqu.happy.module.youqu.controller.admin.userAssess.vo.UserAssessPageReqVO;
import cn.youqu.happy.module.youqu.controller.admin.userAssess.vo.UserAssessUpdateReqVO;
import cn.youqu.happy.module.youqu.controller.app.userAssess.vo.AppUserAssessPublishReqVO;
import cn.youqu.happy.module.youqu.convert.userAssess.UserAssessConvert;
import cn.youqu.happy.module.youqu.dal.dataobject.userArrange.UserArrangeDO;
import cn.youqu.happy.module.youqu.dal.dataobject.userAssess.UserAssessDO;
import cn.youqu.happy.module.youqu.dal.mysql.userAssess.UserAssessMapper;
import cn.youqu.happy.module.youqu.enums.userArrange.UserArrangeStatusEnum;
import cn.youqu.happy.module.youqu.service.userActivity.UserActivityService;
import cn.youqu.happy.module.youqu.service.userArrange.UserArrangeService;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

import static cn.youqu.happy.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.youqu.happy.module.member.enums.ErrorCodeConstants.USER_NOT_EXISTS;
import static cn.youqu.happy.module.youqu.enums.ErrorCodeConstants.*;

/**
 * 用户评价 Service 实现类
 *
 * @author 王其岩 20112001045
 */
@Service
@Validated
public class UserAssessServiceImpl implements UserAssessService {

    @Resource
    private UserAssessMapper userAssessMapper;

    @Resource
    @Lazy
    private MemberUserService memberUserService;

    @Resource
    @Lazy
    private UserActivityService userActivityService;

    @Resource
    @Lazy
    private UserArrangeService userArrangeService;

    @Override
    public Integer publishUserAssess(UserAssessCreateReqVO createReqVO) {
        // 插入
        UserAssessDO userAssess = UserAssessConvert.INSTANCE.convert(createReqVO);
        userAssessMapper.insert(userAssess);
        // 返回
        return userAssess.getId();
    }

    @Override
    public void updateUserAssess(UserAssessUpdateReqVO updateReqVO) {
        // 校验存在
        this.validateUserAssessExists(updateReqVO.getId());
        // 更新
        UserAssessDO updateObj = UserAssessConvert.INSTANCE.convert(updateReqVO);
        userAssessMapper.updateById(updateObj);
    }

    @Override
    public void deleteUserAssess(Integer id) {
        // 校验存在
        this.validateUserAssessExists(id);
        // 删除
        userAssessMapper.deleteById(id);
    }

    private boolean validateUserAssessExists(Integer activityId, Long targetId, Long uid) {
        UserAssessDO userAssessDO = userAssessMapper.findOneByActivityIdAndTargetIdAndUid(activityId, targetId, uid);
        return userAssessDO != null;
    }

    private void validateUserAssessExists(Integer id) {
        if (userAssessMapper.selectById(id) == null) {
            throw exception(USER_ASSESS_NOT_EXISTS);
        }
    }

    private void validateUserAssessExists(Integer id, Long uid) {
        if (userAssessMapper.findByIdAndUid(id, uid) == null) {
            throw exception(USER_ASSESS_NOT_EXISTS);
        }
    }

    private List<UserAssessDO> filterUserCanSeeUserAccess(List<UserAssessDO> userAssessDOS, Long uid) {
        return userAssessDOS.stream().filter(item -> Objects.equals(uid, item.getUid()) || Objects.equals(uid, item.getTargetId())).collect(Collectors.toList());
    }

    @Override
    public UserAssessDO getUserAssess(Integer id) {
        return userAssessMapper.selectById(id);
    }

    @Override
    public List<UserAssessDO> getUserAssessList(Collection<Integer> ids) {
        return userAssessMapper.selectBatchIds(ids);
    }

    @Override
    public PageResult<UserAssessDO> getUserAssessPage(UserAssessPageReqVO pageReqVO) {
        return userAssessMapper.selectPage(pageReqVO);
    }

    @Override
    public List<UserAssessDO> getUserAssessList(UserAssessExportReqVO exportReqVO) {
        return userAssessMapper.selectList(exportReqVO);
    }

    @Override
    public void deleteUserAssess(Integer id, Long loginUserId) {
        this.validateUserAssessExists(id, loginUserId);
        userAssessMapper.deleteById(id);
    }

    @Override
    public UserAssessDO getUserAssess(Integer id, Long loginUserId) {
        return userAssessMapper.findByIdAndUid(id, loginUserId);
    }

    @Override
    public List<UserAssessDO> getUserAssessList(Collection<Integer> ids, Long loginUserId) {
        List<UserAssessDO> userAssessDOS = userAssessMapper.selectBatchIds(ids);
        return filterUserCanSeeUserAccess(userAssessDOS, loginUserId);
    }

    @Override
    public PageResult<UserAssessDO> getUserAssessPage(UserAssessPageReqVO convert, Long loginUserId) {
        PageResult<UserAssessDO> userAssessDOPageResult = userAssessMapper.selectPage(convert);
        List<UserAssessDO> list = userAssessDOPageResult.getList();
        List<UserAssessDO> userAssessDOS = filterUserCanSeeUserAccess(list, loginUserId);
        userAssessDOPageResult.setList(userAssessDOS);
        userAssessDOPageResult.setTotal((long) userAssessDOS.size());

        return userAssessDOPageResult;
    }

    @Override
    public Integer publishUserAssess(AppUserAssessPublishReqVO publishReqVO, Long loginUserId) {

        //不能评价自己
        if (Objects.equals(publishReqVO.getTargetId(), loginUserId)) {
            throw exception(USER_ASSESS_CAN_NOT_ASSESS_YOURSELF);
        }
        List<MemberUserDO> userList = memberUserService.getUserList(Arrays.asList(publishReqVO.getTargetId(), loginUserId));
        Map<Long, MemberUserDO> userDOMap = new HashMap<>();
        userList.forEach(item -> userDOMap.put(item.getId(), item));

        //判断计划是否存在
        UserArrangeDO userArrange0 = userArrangeService.getUserArrange0(publishReqVO.getActivityId());
        if (userArrange0 == null) {
            throw exception(USER_ASSESS_HAVE_NO_POWER_MAKE_ACCESS);
        } else {
            //判断是不是已经完成
            //TODO 完善活动计划时间 展时未加入结束时间
            if (!Objects.equals(userArrange0.getArrangeStatus(), UserArrangeStatusEnum.ARRANGE_ING.getStatus())) {
                //没完成活动不可评价
                throw exception(USER_ASSESS_TIME_NOT_AVAILABLE);
            }
            //判断被评价人是否存在
            if (userDOMap.get(publishReqVO.getTargetId()) == null) {
                throw exception(USER_NOT_EXISTS);
            }

            //判断评价的安排中是否包含评价人和被评价人
            String partners = userArrange0.getPartners();
            List<String> partnerArr = StrUtils.stringConvertToList(partners);
            if (partnerArr.stream().noneMatch(item -> Objects.equals(item, String.valueOf(publishReqVO.getTargetId()))) || partnerArr.stream().noneMatch(item -> Objects.equals(item, String.valueOf(loginUserId)))) {
                //只要有一个不在安排中就不能评价
                throw exception(USER_ASSESS_HAVE_NO_POWER_MAKE_ACCESS);
            }

            //判断是否评价过
            if (this.validateUserAssessExists(publishReqVO.getActivityId(), publishReqVO.getTargetId(), loginUserId)) {
                //已经评价过
                throw exception(USER_ASSESS_ALREADY_ASSESS);
            }

            UserAssessDO convert = UserAssessConvert.INSTANCE.convert(publishReqVO);
            //设置用户id
            convert.setUid(loginUserId);
            //设置头像
            convert.setAvatar(userDOMap.get(loginUserId).getAvatar());
            //设置用户名
            convert.setNickName(userDOMap.get(loginUserId).getNickname());

            userAssessMapper.insert(convert);
            return convert.getId();
        }
    }

    @Override
    public void updateUserInfoToUserAssess(String nickname, String avatar, Long uid) {
        if (nickname != null) userAssessMapper.updateNickNameByUid(nickname, uid);
        if (avatar != null) userAssessMapper.updateAvatarByUid(avatar, uid);

    }
}
